/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler.properties;

import com.funcom.peeler.PeelStyleSheet;
import com.funcom.peeler.UpdateCont;
import com.funcom.peeler.WorkBench;
import com.funcom.peeler.action.Move;
import com.funcom.peeler.action.NameChange;
import com.funcom.peeler.action.Resize;
import com.funcom.peeler.action.StyleClassChange;
import com.funcom.peeler.adapter.KeyAndMouseAdapter;
import com.funcom.peeler.peelable.PeelComponent;
import com.funcom.peeler.utils.NumberErrorMessage;
import com.funcom.peeler.utils.SwingMessages;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Set;

import static com.funcom.peeler.UpdateCont.get;

public class DefaultTextFields extends UpdateableProperties {

    public static final int NAME   = 4;
    public static final int STYLE  = 5;
    public static final int SIZE_X = 0;
    public static final int SIZE_Y = 1;
    public static final int LOC_X  = 2;
    public static final int LOC_Y  = 3;

    public static final int LENGTH = 6;

    JLabel element;
    JLabel parent;
    JTextField[] textFields;

    private WorkBench workBench;

    String[] nameAndStyleA = new String[]{"",""};

    boolean nameAndStyle = false;

    int[] lastGeometricState = new int[LENGTH - 2];

    public DefaultTextFields(JTextField[] textFields, JLabel element, JLabel parent) {
        this.textFields = textFields;
        this.element = element;
        this.parent = parent;

        initListeners();
    }

    public void update() {
        fields_cleared = false;
        setTextFields();
    }

    public void needUpdate( WorkBench workBench,
                            Set<PeelComponent> allComp,
                            Set<PeelComponent> selectedComps,
                            PeelComponent main_selected,
                            PropertiesFrame thisFrame ) {

        this.workBench = workBench;

        if (main_selected == null) {
            selectedComp = null;
            if (!fields_cleared) {
                clear();
                return;
            } else {
                return;
            }
        }

        if (selectedComp != main_selected) {
            wantUpdate = true;
            selectedComp = main_selected;

        } else {


            if ( !nameAndStyleA[0].equals(selectedComp.getComponent().getName())) {
                wantUpdate = true;
            }
            if (!nameAndStyleA[1].equals(selectedComp.getComponent().getStyleClass())) {
                wantUpdate = true;
            }
            else if (lastGeometricState[SIZE_X] != selectedComp.getComponent().getWidth()) {
                wantUpdate = true;
            }
            else if (lastGeometricState[SIZE_Y] != selectedComp.getComponent().getHeight()) {
                wantUpdate = true;
            }
            else if (lastGeometricState[LOC_X] != selectedComp.getComponent().getX()) {
                wantUpdate = true;
            }
            else if (lastGeometricState[LOC_Y] != selectedComp.getComponent().getY()) {
                wantUpdate = true;
            }
        }
        if (fields_cleared) {
            wantUpdate = true;
        }
    }

    public void applyChange( PeelComponent component, PropertiesFrame updater) {

        switch (change) {

            case NAME: {

                UpdateCont.get().getFocusedWorkBench().pushChange( new NameChange( component,
                                                                                   component.getComponent().getName(),
                                                                                   textFields[NAME].getText() ) );
                component.getComponent().setName(textFields[NAME].getText());

                break;
            }
            case NEW_STYLE: {

                String newStyle = textFields[STYLE].getText();

                PeelStyleSheet styleSheet = (PeelStyleSheet) component.getComponent().getWindow().getStyleSheet();
                String previousStyle = component.getComponent().getStyleClass();

                if (!styleSheet.makeNewStyleFromPrevious( newStyle, component )) {

                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            SwingMessages.textError(SwingMessages.WRONG_STYLE);
                        }
                    });

                    textFields[STYLE].setText(previousStyle);
                } else {

                    UpdateCont.get().getFocusedWorkBench().pushChange( new StyleClassChange( component, previousStyle, newStyle ) );
                    get().invalidateComponent(component, true, newStyle);

                }
                break;
            }
            case SIZE: {

                if (component.isLocked()) return;

                int width = component.getComponent().getWidth();
                int height = component.getComponent().getHeight();

                Resize resize = new Resize( component );
                resize.startChange();

                try {
                    width = Integer.parseInt(textFields[SIZE_X].getText());
                    height = Integer.parseInt(textFields[SIZE_Y].getText());

                    if (width < 0) {
                        width = component.getComponent().getWidth();
                    }
                    if (height < 0) {
                        height = component.getComponent().getHeight();
                    }

                } catch (NumberFormatException e) {
                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            NumberErrorMessage.numberError("Not a valid number");
                        }
                    });
                    textFields[SIZE_X].setText(String.valueOf(component.getComponent().getWidth()));
                    textFields[SIZE_Y].setText(String.valueOf(component.getComponent().getHeight()));
                }

                component.getComponent().setSize(width, height);
                resize.endChange();
                UpdateCont.get().getFocusedWorkBench().pushChange( resize );

                break;
            }
            case POSITION: {

                if (component.isLocked()) return;

                int loc_x = component.getComponent().getX();
                int loc_y = component.getComponent().getY();

                Move move = new Move( component );
                move.startChange();

                try {
                    loc_x = Integer.parseInt(textFields[LOC_X].getText());
                    loc_y = Integer.parseInt(textFields[LOC_Y].getText());

                    //Just too keep input above allowed values
                    if (loc_x < 0) {
                        loc_x = component.getComponent().getAbsoluteX();
                    }
                    if (loc_y < 0) {
                        loc_y = component.getComponent().getAbsoluteY();
                    }

                } catch (NumberFormatException e) {
                    SwingUtilities.invokeLater( new Runnable() {
                        public void run() {
                            NumberErrorMessage.numberError("Not a valid number");
                        }
                    });
                    textFields[LOC_X].setText(String.valueOf(component.getComponent().getX()));
                    textFields[LOC_Y].setText(String.valueOf(component.getComponent().getY()));
                }

                component.getComponent().setLocation(loc_x, loc_y);
                move.endChange();
                UpdateCont.get().getFocusedWorkBench().pushChange( move );

                break;
            }
        }
    }

    public void clear() {
        clearTextFields();
    }

    private void setTextFields() {

        if (selectedComp == null) return;

        element.setText(selectedComp.getClass().getSimpleName());

        PeelComponent tempParent = selectedComp.getParent();

        if (tempParent == null) return;

        parent.setText( tempParent.getComponent().getName() );

        nameAndStyleA[0] = selectedComp.getComponent().getName(); //textFields[NAME].getText();
        nameAndStyleA[1] = selectedComp.getComponent().getStyleClass(); //textFields[STYLE].getText();

        textFields[NAME].setText(selectedComp.getComponent().getName());
        textFields[STYLE].setText(selectedComp.getComponent().getStyleClass());

        lastGeometricState[SIZE_X] = selectedComp.getComponent().getBounds().width;
        lastGeometricState[SIZE_Y] = selectedComp.getComponent().getBounds().height;
        lastGeometricState[LOC_X] = selectedComp.getComponent().getX();
        lastGeometricState[LOC_Y] = selectedComp.getComponent().getY();

        textFields[SIZE_X].setText(Integer.toString(selectedComp.getComponent().getBounds().width));
        textFields[SIZE_Y].setText(Integer.toString(selectedComp.getComponent().getBounds().height));
        textFields[LOC_X].setText(Integer.toString(selectedComp.getComponent().getX()));
        textFields[LOC_Y].setText(Integer.toString(selectedComp.getComponent().getY()));
    }

    private void clearTextFields() {

        element.setText("");
        parent.setText("");

        for (JTextField aField : textFields) {
            aField.setText("");
        }
        fields_cleared = true;
    }

    protected void initListeners() {

        FieldListener listener = new FieldListener();
        FieldFocusListener focusListener = new FieldFocusListener();

        for (JTextField aField : textFields) {
            aField.addActionListener(listener);
        }
        textFields[SIZE_X].addFocusListener(focusListener);
        textFields[SIZE_Y].addFocusListener(focusListener);
        textFields[LOC_X].addFocusListener(focusListener);
        textFields[LOC_Y].addFocusListener(focusListener);
    }

    private class FieldFocusListener extends KeyAndMouseAdapter {
        public void focusGained(FocusEvent e) {
        }

        public void focusLost(FocusEvent e) {
            if (e.getSource() == textFields[NAME]) {
                change = ChangeProp.NAME;
            }
            if (e.getSource() == textFields[STYLE]) {
                change = ChangeProp.NEW_STYLE;
            }
            if (e.getSource() == textFields[SIZE_X] || e.getSource() == textFields[SIZE_Y]) {
                change = ChangeProp.SIZE;
            }

            if (e.getSource() == textFields[LOC_X] || e.getSource() == textFields[LOC_Y]) {
                change = ChangeProp.POSITION;
            }
        }
    }

    private class FieldListener implements ActionListener {

        public void actionPerformed( ActionEvent e) {
            if (e.getSource() == textFields[NAME]) {
                change = ChangeProp.NAME;
            }
            if (e.getSource() == textFields[STYLE]) {
                change = ChangeProp.NEW_STYLE;
            }
            if (e.getSource() == textFields[SIZE_X] || e.getSource() == textFields[SIZE_Y]) {
                change = ChangeProp.SIZE;
            }

            if (e.getSource() == textFields[LOC_X] || e.getSource() == textFields[LOC_Y]) {
                change = ChangeProp.POSITION;
            }
        }
    }
}
